package com.young.core.manager.impl;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

import com.young.core.dao.NodeDao;
import com.young.core.domain.NodeDO;
import com.young.core.manager.NodeManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;


@Component
public class NodeManagerImpl implements NodeManager {

    private static final String PREFIX_ID = "_NODE_";

    private static final Cache<String, List<NodeDO>> NODE_CACHE = CacheBuilder.newBuilder().recordStats()
            .concurrencyLevel(Runtime.getRuntime().availableProcessors() + 2)
            .initialCapacity(128)
            .maximumSize(4096)
            .expireAfterWrite(6, TimeUnit.SECONDS)
            .build();

    @Autowired
    private NodeDao nodeDao;

    private String key(String project) {
        return PREFIX_ID + project;
    }

    @Override
    public List<NodeDO> getAliveCache(String project, int ttl) throws ExecutionException {
        return NODE_CACHE.get(key(project), () -> getAlive(project, ttl));
    }

    @Override
    public void upsert(NodeDO node) {
        NodeDO current = getSpecific(node);
        if (current == null) {
            nodeDao.insert(node);
        } else {
            node.setId(current.getId());
            nodeDao.update(node);
        }
    }

    @Override
    public Collection<NodeDO> getAll(String project) {
        return nodeDao.getAll(project);
    }

    @Override
    public List<NodeDO> getAlive(String project, int ttl) {
        return this.nodeDao.getAlive(project, ttl);
    }

    @Override
    public int delete(NodeDO node) {
        NodeDO current = this.getSpecific(node);
        return current == null ? 0 : this.nodeDao.delete(current.getId());
    }

    @Override
    public int expire(long ttl) {
        return nodeDao.expire(ttl);
    }

    private NodeDO getSpecific(NodeDO condition) {
        if (condition.getInstanceId() != null) {
            return this.nodeDao.getSpecific(condition.getInstanceId());
        }
        return this.nodeDao.getSpecific(condition.getProject(), condition.getIp(), condition.getPort());
    }
}
